#include <stdio.h>
#include <string.h>
#include <sys/types.h> //open
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>  //close
#include <sys/mman.h> //mmap
#include <string.h>
#include <stdlib.h>


/*
    800*480的bmp图片的大小
    addr:lcd映射的地址
    bmp_path:bmp的路径名
*/
int show_bmp(int *addr,char *bmp_path)
{
   //标准IO，打开BMP图片
    FILE *fp_bmp = fopen(bmp_path, "rb");
    if(fp_bmp == NULL)
    {
        printf("fopen bmp fail\n");
        return -1;
    }

    //读取BMP图片的数据
    //跳过BMP图片的头54个字节
    fseek(fp_bmp,54,SEEK_SET);
    //从第54个字节开始读800*480*3字节数
    char *pbuf = (char *)malloc(sizeof(char) * 800 * 480 * 3);
    memset(pbuf, 0, 800 * 480 *3);

    //将800*480的图片数据读到缓冲区
    fread(pbuf, 1, 800*480*3, fp_bmp);

    //直接通过mmap这个函数映射的地址来给LCD刷颜色
    int x = 0; //横轴
    int y = 0; //纵轴
    for(y=0;y<480;y++)
    {
        //通过映射的地址来指向LCD上每一个像素点，然后解引用赋值
        for(x=0;x<800;x++)
            // *(addr+y*800+x) = buf[xy表达式] | buf[xy表达式]<<8 | buf[xy表达式]<<16 
            //LCD的最后一行 = BMP的第一行
            *(addr+(479-y)*800+x) = pbuf[(y*800+x)*3+0] |
                                pbuf[(y*800+x)*3+1]<<8 |
                                pbuf[(y*800+x)*3+2]<<16;
    }

    //关闭BMP文件、
    fclose(fp_bmp);  
    free(pbuf);
}


/*
    任意大小的bmp照片长宽必须是4的倍数
    addr:lcd映射的地址
    bmp_path:bmp的路径名
    offset_x:lcd的起始位置x坐标
    offset_y:lcd的起始位置y坐标
*/
int show_bmp_size(int *addr,char *bmp_path,int offset_x,int offset_y)
{
    //打开BMP图片
    //标准IO，打开BMP图片
    FILE *fp_bmp = fopen(bmp_path, "rb");
    if(fp_bmp == NULL)
    {
        printf("fopen bmp fail\n");
        return -1;
    }

    //保证读取图片的光标在开头
    fseek(fp_bmp, 0 ,SEEK_SET);

    //读取BMP图片的的大小
    int width = 0;//宽度
    int height = 0;//高度
    fseek(fp_bmp,18,SEEK_SET);
    fread(&width, 1, 4, fp_bmp);
    fread(&height, 1, 4, fp_bmp);
    printf("width:%d height:%d\n", width, height);

    //读取bmp图片的数据
    fseek(fp_bmp, 54, SEEK_SET);
    char *pbuf = (char *)malloc(sizeof(char) * width * height * 3);
    fread(pbuf, 1, width*height*3, fp_bmp);

    //bmp图片的起始位置坐标(offset_x,offset_y)
    // int offset_x = 100;
    // int offset_y = 100;

    int x = 0; //横轴
    int y = 0; //纵轴
    for(y=0;y<height;y++)
    {
        //通过映射的地址来指向LCD上每一个像素点，然后解引用赋值
        for(x=0;x<width;x++)
            //LCD的最后一行 = BMP的第一行
            *(addr+(offset_y+height-1-y)*800+offset_x+x) = pbuf[(y*width+x)*3+0] |
                                pbuf[(y*width+x)*3+1]<<8 |
                                pbuf[(y*width+x)*3+2]<<16;
    }


    //关闭BMP文件、
    fclose(fp_bmp);
    free(pbuf);

}


int main(int argc,char **argv)
{
    //打开LCD文件
    int fd_lcd = open("/dev/fb0",O_RDWR);
    if(fd_lcd < 0)
    {
        printf("open lcd fail\n");
        return -1;
    }

    //LCD的映射
    int *addr = mmap(NULL, //If addr is NULL, then the kernel chooses the address
                     800*480*4, //LCD的大小
                     PROT_READ|PROT_WRITE,//LCD的权限
                     MAP_SHARED,//标志量
                     fd_lcd, //LCD的文件描述符
                     0); //LCD的偏移量
    if(addr == NULL)
    {
        printf("mamp fail\n");
        return -1;
    }

    
    //显示一张800*480的bmp图片(背景图)
     show_bmp(addr,"IKUN.bmp");
    #if 1
    while(1)
    {
        //在坐标(100,100)的地方放了一张xxx.bmp的图片
        show_bmp_size(addr,"giao.bmp",0,0);
        sleep(1);
        show_bmp_size(addr,"dingzhen.bmp",0,0);
        sleep(1);
    }
    #endif


    //LCD映射的释放
    munmap(addr,800*480*4);
    //关闭LCD文件
    close(fd_lcd);

    return 0;
}